#ifndef OBJECT_MANAGER_H
#define OBJECT_MANAGER_H

#include <vector>
#include <map>
#include <string>

template< typename VT >
struct VertexBuffer {
  typedef VT VertexType;
  VertexBuffer() : vertCount(0), verts(NULL) {}

  unsigned int vertCount;
  const VT* verts;
};

template< typename VT >
struct ReferenceObject {
  typedef VT VertexType;
  ReferenceObject() : isStatic(false), refCount(0) {}

  bool isStatic; // if true, do not delete object when there are no references
  unsigned int refCount;
  VertexBuffer<VT> buffer;
  std::string objectName;
};

template< typename TT, typename VT >
class ObjectManager;

// Object< transforms, vector3f >
// transforms may contain rotations, scales, etc.
template< typename TT, typename VT >
class Object {
  public:
    typedef TT TransformType;
    typedef VT VertexType;

    Object() : vertexBuffer(NULL), vertexIndex(0) {}
    const VT operator[]( unsigned int pos );

    TransformType transformInfo;

  private:
    friend class ObjectManager<TT,VT>;
    const VertexBuffer<VT> * vertexBuffer;
    unsigned int vertexIndex;
};

template< typename TT, typename VT >
class ObjectManager {
  public:
    typedef TT TransformType;
    typedef VT VertexType;
    typedef unsigned int IdValue;
    typedef ReferenceObject<VT> RefObj;
    typedef Object<TT,VT> Obj;
    typedef VT* (*CreateFunc)( const char*, unsigned int& vertCount );

    ObjectManager( CreateFunc func );
    ~ObjectManager();

    Obj CreateObject( std::string objectName );
    void DeleteObject( Obj& object );
    void ChangeObject( Obj& object, std::string objectName );

    void GenerateObject( std::string objectName, std::string dataFile, bool isStatic = false );

  private:
    typedef std::pair<std::string, IdValue> StrIdPair;
    typedef std::map<std::string, IdValue> StrIdMap;
    typedef StrIdMap::iterator StrIdIter;

    ObjectManager();
    ObjectManager( ObjectManager& );

    IdValue GetNewLoc();
    void ReleaseLoc( IdValue val );

    std::vector< RefObj > objectRefs; // Holds unmodified vertices and reference counts
    IdValue currentLoc; // Largest value that can access the array
    std::vector<IdValue> deletedLocs; // Locations of deleted buffers are stored
                                      //   upon a non-static object deletions.
                                      // Accessed upon new object creation
    StrIdMap nameToId; // name of object is mapped to its ID
    
    CreateFunc CreateBufferFromFile;
};

#include "ObjectManagerCode.h"

#endif

/*
ObjectManager
- CreateObject(ID/Name) // ID is dangerous to use
  * creates an object or refers/points to an already created object
  * increases reference count for the given object
- DestroyObject( object* )
  * decreases the reference count for the given object
  * if not marked as static and not referenced, delete the object
    * statics will remain until program ends

- GenerateBasicObject( object name, extra...-slices, stacks- )?
  * "triangle", "plane", etc.
  * only generated if called for

- GenerateObject( object name, file name, style -Strips,Triangles-? )
  * returns ID value for that object
  * relate object names and object ID
    * "none" -> 0 // default
    * "arm" -> 1
    * "leg" -> 2
  * create new ID for each object, store removed IDs for grabbing later
    * ID set // always increments
    * removed ID set // remove first element if new object created
    ! never overlaps unless ID set is full because removed list must be empty to
      increment ID set
    ! reference counting means objects shouldn't be looking for deleted vertices


ObjectHandler
- stores rotation, scale and translation ( anything else? )
- applies those to the vertices pointed to before drawing ( vertices unaltered
- any operation that alters vertices ( move a vert, but not the rest ) creates a
  new object
  * new object is not static, because of chance for constant changes (ie. memory
    overflow)
*/

/*
  use getTime for timers
  QueryPerformance for function runtimes (short burst)
*/
